import dayjs = require("dayjs");
import { addPicture } from "../../entity/picture";
import { joinDefaultFields } from "../../utils";
import * as Koa from 'koa';

const http = require("http");
const aliyunOss = require("./aliyun-oss");
const configs = require('./config');
const OSS = require('ali-oss');
const uuid = require("uuid");
const imageinfo = require("imageinfo"); // 引用imageinfo模块
const fs = require('fs');
// TODO：commonjs 模式下引用 esmodule 模块
let nanoid: any = null;
(async () => {
  nanoid = (await eval("import('nanoid')")).nanoid;
})();

export class OssService {
  private uploadFileClient: any = null; // 上传文件的OSS对象
  private inputFilepath: string; // 输入文件路径
  private outputFilePath: string; // 输出文件路径
  private options: any = {}; // 图片参数

  private koaObj = null;

  constructor(inputFilepath: string, outputFilePath: string, options: Object) {
    this.inputFilepath = inputFilepath;
    this.outputFilePath = outputFilePath;
    this.options = options;
  }

  private saveLog(data: Object) {
    console.log("========上传日志", data);
  }

  private async uploadFile(client) {
    if (!this.uploadFileClient || Object.keys(this.uploadFileClient).length === 0) {
      this.uploadFileClient = client;
    }
    // ？？？清空上传图片的日志【存储格式为：userId：哪个用户上传的；ind：上传的第几个图片；result：上传结果（成功或失败）；msg：上传失败的原因】

    // 日志信息
    const uploadTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
    const logInfo: any = {
      uploadTime: uploadTime,
      userId: "",
      id: uuid.v4(),
      filename: this.options.name || "",
    };
    if (!this.options.name) {
      logInfo.msg = "文件名为空";
      logInfo.result = false;
      return logInfo;
    } else if (!this.outputFilePath) {
      logInfo.msg = "输出文件路径为空";
      logInfo.result = false;
      return logInfo;
    }
    let ossResult: any = null;
    try {
      ossResult = await this.uploadFileClient.put(this.outputFilePath + "/" + this.options.name, this.inputFilepath); // 返回的远程 url 地址
      logInfo.msg = ossResult ? "上传oss服务成功" : "上传oss服务失败";
      logInfo.result = !!ossResult;
      if (!logInfo.result) return logInfo;
    } catch (error) {
      logInfo.msg = "上传oss服务失败";
      logInfo.result = false;
      return logInfo;
    }
    try {
      // 将上送成功的图片信息保存到数据库中
      const pictureInfo = imageinfo(fs.readFileSync(this.inputFilepath));
      // 读取完毕后立即删除图片
      fs.unlink(this.inputFilepath, _ => _);
      if (!pictureInfo.mimeType) {
        logInfo.msg = "上传后端服务失败";
        logInfo.result = false;
        return logInfo;
      }
      const picture = {
        name: this.options.name || "",
        title: this.options.name || "",
        picel_width: pictureInfo.width + "px",
        picel_height: pictureInfo.height + "px",
        wh_radio: ((pictureInfo.width / pictureInfo.height) as any).toFixed(2) - 0,
        url: ossResult.url || "",
        remote_file_path: ossResult.name || "",
        capture_time: this.options.captureTime || "",
        is_origin: this.options.isOrigin || "",
      };
      const _picture = joinDefaultFields(picture, 'pictureFields');
      _picture.pid = nanoid(18);
      _picture.create_time = dayjs().format("YYYY-MM-DD HH:mm:ss");
      const result: any = _picture && (await addPicture(this.koaObj, _picture));
      if (!result?.success) {
        logInfo.msg = result.msg || "上传后端服务失败";
        logInfo.result = false;
        return logInfo;
      } else {
        logInfo.msg = "成功";
        logInfo.result = true;
        return logInfo;
      }
    } catch (error) {
      logInfo.msg = "上传后端服务失败";
      logInfo.result = false;
      return logInfo;
    }
  };

  /**
   * 创建一个 OSS 对象，然后进行图片上传；
   * @param {*} isRefresh 是否重新加载OSS对象
   */
  private async applyTokenDo(isRefresh: boolean) {
    let logInfo: any = null;
    if (isRefresh) {
      // 调用STS加密，得到token；
      const result = await aliyunOss();
      // 获取OSS服务对象【这里会存在调用OSS跨域问题，到阿里云bucket中去设置允许跨域】
      const client = new OSS({
        region: configs.region,
        accessKeyId: result.AccessKeyId,
        accessKeySecret: result.AccessKeySecret,
        stsToken: result.SecurityToken,
        bucket: configs.bucket,
      });
      logInfo = await this.uploadFile(client);
    } else {
      logInfo = await this.uploadFile(null);
    }
    this.saveLog(logInfo);
    return logInfo;
  };
  
  public async send(ctx: Koa.Context) {
    this.koaObj = ctx;
    return await this.applyTokenDo(!this.uploadFileClient);
  }
}
